package com.heima.wemedia.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmChannelDto;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.service.WmChannelService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @Description TODO
 * @Author bo.li
 * @Date 2023/3/16 10:51
 * @Version 1.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class WmChannelServiceImpl extends ServiceImpl<WmChannelMapper, WmChannel> implements WmChannelService {
    private final WmChannelMapper wmChannelMapper;
    private final StringRedisTemplate stringRedisTemplate;
    /**
     * 查询出所有的频道
     * @return
     */
    @Override
    public ResponseResult findAll() {
        return ResponseResult.okResult(list());
    }

    /**
     * 分页查询所有频道
     * @param wmChannelDto
     * @return
     */
    @Override
    public ResponseResult PageChannel(WmChannelDto wmChannelDto) {
        //检查查询
        wmChannelDto.checkParam();

        String sizeString = stringRedisTemplate.opsForValue().get("wmChannelsize");
        if (!StringUtils.isEmpty(sizeString)) {
            if (wmChannelDto.getSize() == Integer.parseInt(sizeString)) {
                HashMap map = redisGetByKey(wmChannelDto.getPage());
                List<WmChannel> wmChannelList = (List<WmChannel>) map.get("wmChannel");
                String total = (String) map.get("total");
                if (!ObjectUtils.isEmpty(wmChannelList) && !StringUtils.isEmpty(total)) {
                    PageResponseResult result = new PageResponseResult(wmChannelDto.getPage(), wmChannelDto.getSize(), Integer.parseInt(total));
                    result.setData(wmChannelList);
                    return result;
                }
            } else {
                deleteRedis();
            }
        }

        Page<WmChannel> page = new Page(wmChannelDto.getPage(),wmChannelDto.getSize());
        //构造查询条件
        LambdaQueryWrapper<WmChannel> wrapper = new LambdaQueryWrapper<>();
        //精确查询状态
        wrapper.eq(!StringUtils.isEmpty(wmChannelDto.getStatus()),WmChannel::getStatus,wmChannelDto.getStatus());
        //模糊查询频道名称
        wrapper.like(!ObjectUtils.isEmpty(wmChannelDto.getName()),WmChannel::getName,wmChannelDto.getName());
        //根据创建时间倒叙查询
        wrapper.orderByDesc(WmChannel::getCreatedTime);
        page(page,wrapper);
        PageResponseResult result = new PageResponseResult(wmChannelDto.getPage(), wmChannelDto.getSize(), (int) page.getTotal());
        //获取数据
        result.setData(page.getRecords());

        stringRedisTemplate.opsForValue().set("wmChanneltotal", String.valueOf(page.getTotal()));
        stringRedisTemplate.opsForValue().set("wmChannelsize", String.valueOf(wmChannelDto.getSize()));

        for (WmChannel wmChannel : page.getRecords()) {
            stringRedisTemplate.opsForValue().set("wmChannel:" + wmChannelDto.getPage() + ":" + wmChannel.getId(), JSON.toJSONString(wmChannel));
        }
        return result;
    }

    /**
     * 获取
     *
     * @return
     */
    private HashMap redisGetByKey(Integer page) {
        Set<String> wmChannelKeySet = stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> keys = new HashSet<>();
            Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match("wmChannel:" + page + ":*").count(1000).build());
            while (cursor.hasNext()) {
                keys.add(new String(cursor.next()));
            }
            return keys;
        });
        List<WmChannel> wmChannels = new ArrayList<>();
        for (String wmChannelKey : wmChannelKeySet) {
            String wmChannelJson = stringRedisTemplate.opsForValue().get(wmChannelKey);
            WmChannel wmChannel = JSON.parseObject(wmChannelJson, WmChannel.class);
            wmChannels.add(wmChannel);
        }
        String total = stringRedisTemplate.opsForValue().get("wmChanneltotal");
        HashMap<String, Object> map = new HashMap<>();
        map.put("wmChannel", wmChannels);
        map.put("total", total);
        return map;
    }

    /**
     * 删除
     */
    private void deleteRedis() {
        Set<String> wmChannelKeySet = stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> keys = new HashSet<>();
            Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match("wmChannel*").count(1000).build());
            while (cursor.hasNext()) {
                keys.add(new String(cursor.next()));
            }
            return keys;
        });
        if (ObjectUtils.isEmpty(wmChannelKeySet)) {
            return;
        }
        for (String wmChannelKey : wmChannelKeySet) {
            stringRedisTemplate.delete(wmChannelKey);
        }
        stringRedisTemplate.delete("wmChannelsize");
        stringRedisTemplate.delete("wmChanneltotal");
    }
    /**
     * 删除频道
     * @param
     * @param id
     * @return
     */
    @Override
    public ResponseResult delChannl( Integer id) {
        WmChannel channel = wmChannelMapper.selectById(id);
        if (channel.getStatus().equals(true)){
            return ResponseResult.errorResult(AppHttpCodeEnum.CHANNEL_ACTIVE);
        }
        wmChannelMapper.deleteById(id);
        deleteRedis();
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
    /**
     * 修改频道
     * @param wmChannelDto
     * @return
     */
    @Override
    public ResponseResult updateChannel(WmChannelDto wmChannelDto) {
        WmChannel channel = new WmChannel();
        BeanUtils.copyProperties(wmChannelDto,channel);
        channel.setName(wmChannelDto.getName());
        channel.setDescription(wmChannelDto.getDescription());
        channel.setOrd(wmChannelDto.getOrd());
        LambdaQueryWrapper<WmChannel> wrapper = new LambdaQueryWrapper<>();
        Integer count = wmChannelMapper.selectCount(wrapper.eq(!ObjectUtils.isEmpty(wmChannelDto.getId()),WmChannel::getId,wmChannelDto.getId()));
        if (ObjectUtils.isEmpty(count)){
            return ResponseResult.errorResult(AppHttpCodeEnum.CHANNEL_CITED);
        }
        if (wmChannelDto.getStatus().equals(true)){
            channel.setStatus(true);
        }else if (wmChannelDto.getStatus().equals(false)){
            channel.setStatus(false);
        }
        wmChannelMapper.updateById(channel);
        deleteRedis();
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
    /**
     * 新增频道
     */
    @Override
    public ResponseResult saveChannel(WmChannelDto wmChannelDto) {
        if (ObjectUtils.isEmpty(wmChannelDto)){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        LambdaQueryWrapper<WmChannel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(!StringUtils.isEmpty(wmChannelDto.getName()),WmChannel::getName,wmChannelDto.getName());
        List<WmChannel> wmChannels = wmChannelMapper.selectList(wrapper);
        if (!CollectionUtils.isEmpty(wmChannels)){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST);
        }
        WmChannel channel = new WmChannel();
        BeanUtils.copyProperties(wmChannelDto,channel);
        channel.setName(wmChannelDto.getName());
        channel.setDescription(wmChannelDto.getDescription());
        channel.setOrd(wmChannelDto.getOrd());
        channel.setIsDefault(true);
        channel.setCreatedTime(new Date());
        if (wmChannelDto.getStatus().equals(true)){
            channel.setStatus(true);
        }else if (wmChannelDto.getStatus().equals(false)){
            channel.setStatus(false);
        }
        wmChannelMapper.insert(channel);
        deleteRedis();
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}